// internal/apps/auth/services/auth_service.go
package services

import (
	"errors"
	"fmt"
	"star-go-app/internal/apps/auth/models"
	"star-go-app/internal/apps/auth/repositories"
	"star-go-app/internal/apps/auth/serializers"
	"star-go-app/pkg/common/utils/jwt"
	"star-go-app/pkg/infra/config"
	"time"

	"golang.org/x/crypto/bcrypt"
)

// AuthService 认证服务接口
type AuthService interface {
	// 用户登录
	Login(request *serializers.LoginRequest, clientInfo ClientInfo) (*serializers.TokenResponse, error)
	// 刷新token
	RefreshToken(request *serializers.RefreshTokenRequest, clientInfo ClientInfo) (*serializers.TokenResponse, error)
	// 验证token并获取用户信息
	VerifyToken(token string) (*serializers.AuthUserInfoResponse, error)
	// 登出
	Logout(accessToken string) error
}

// ClientInfo 客户端信息
type ClientInfo struct {
	IPAddress  string // IP地址
	UserAgent  string // 用户代理
	DeviceInfo string // 设备信息
}

// authService 认证服务实现
type authService struct {
	authRepo repositories.AuthRepository
}

// NewAuthService 创建认证服务实例
func NewAuthService() AuthService {
	return &authService{
		authRepo: repositories.NewAuthRepository(),
	}
}

// Login 用户登录
func (s *authService) Login(request *serializers.LoginRequest, clientInfo ClientInfo) (*serializers.TokenResponse, error) {
	// 根据用户名获取用户信息
	user, err := s.authRepo.GetUserByUsername(request.Username)
	if err != nil {
		return nil, errors.New("用户名或密码错误")
	}

	// 验证密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(request.Password)); err != nil {
		return nil, errors.New("用户名或密码错误")
	}

	// 检查用户状态
	if user.Status != 1 {
		return nil, errors.New("用户账号已被禁用")
	}

	// 生成访问令牌和刷新令牌
	accessToken, err := jwt.GenerateAccessToken(user.ID)
	if err != nil {
		return nil, fmt.Errorf("生成访问令牌失败: %v", err)
	}

	refreshToken, err := jwt.GenerateRefreshToken(user.ID)
	if err != nil {
		return nil, fmt.Errorf("生成刷新令牌失败: %v", err)
	}

	cfg := config.GetConfig().JWT

	// 根据配置决定是否创建登录会话记录
	if cfg.EnableAdvancedAuth {
		session := &models.LoginSession{
			UserID:       user.ID,
			AccessToken:  accessToken,
			RefreshToken: refreshToken,
			DeviceInfo:   clientInfo.DeviceInfo,
			IPAddress:    clientInfo.IPAddress,
			UserAgent:    clientInfo.UserAgent,
			LoginTime:    time.Now(),
			ExpiresAt:    time.Now().Add(time.Duration(cfg.RefreshTokenExp) * time.Minute),
			IsActive:     true,
			LastActivity: time.Now(),
		}

		if err := s.authRepo.CreateLoginSession(session); err != nil {
			return nil, fmt.Errorf("创建登录会话失败: %v", err)
		}
	}

	return &serializers.TokenResponse{
		AccessToken:  accessToken,
		RefreshToken: refreshToken,
		TokenType:    "Bearer",
		ExpiresIn:    int64(cfg.AccessTokenExp * 60), // 转换为秒
	}, nil
}

// RefreshToken 刷新访问令牌
func (s *authService) RefreshToken(request *serializers.RefreshTokenRequest, clientInfo ClientInfo) (*serializers.TokenResponse, error) {
	// 验证刷新令牌
	claims, err := jwt.ParseRefreshToken(request.RefreshToken)
	if err != nil {
		return nil, errors.New("无效的刷新令牌")
	}

	cfg := config.GetConfig().JWT

	// 根据配置决定是否使用高级认证功能
	if cfg.EnableAdvancedAuth {
		// 检查黑名单
		isBlacklisted, err := s.authRepo.IsTokenBlacklisted(request.RefreshToken)
		if err != nil {
			return nil, fmt.Errorf("检查令牌黑名单失败: %v", err)
		}
		if isBlacklisted {
			return nil, errors.New("刷新令牌已失效")
		}

		// 检查登录会话
		session, err := s.authRepo.GetLoginSessionByRefreshToken(request.RefreshToken)
		if err != nil {
			return nil, errors.New("无效的刷新令牌")
		}

		// 验证会话是否属于同一用户
		if session.UserID != claims.UserID {
			return nil, errors.New("无效的刷新令牌")
		}

		// 生成新的访问令牌
		newAccessToken, err := jwt.GenerateAccessToken(claims.UserID)
		if err != nil {
			return nil, fmt.Errorf("生成新访问令牌失败: %v", err)
		}

		// 将旧的访问令牌加入黑名单
		expiresAt := time.Now().Add(time.Duration(cfg.AccessTokenExp) * time.Minute)
		if err := s.authRepo.AddTokenToBlacklist(session.AccessToken, "access", claims.UserID, "token_refresh", expiresAt); err != nil {
			return nil, fmt.Errorf("添加旧令牌到黑名单失败: %v", err)
		}

		// 更新会话中的访问令牌和活动时间
		session.AccessToken = newAccessToken
		session.LastActivity = time.Now()
		if err := s.authRepo.UpdateLoginSessionActivity(session.ID, time.Now()); err != nil {
			return nil, fmt.Errorf("更新会话活动时间失败: %v", err)
		}

		return &serializers.TokenResponse{
			AccessToken:  newAccessToken,
			RefreshToken: request.RefreshToken,
			TokenType:    "Bearer",
			ExpiresIn:    int64(cfg.AccessTokenExp * 60), // 转换为秒
		}, nil
	} else {
		// 简化模式：直接生成新的访问令牌，不检查会话和黑名单
		newAccessToken, err := jwt.GenerateAccessToken(claims.UserID)
		if err != nil {
			return nil, fmt.Errorf("生成新访问令牌失败: %v", err)
		}

		return &serializers.TokenResponse{
			AccessToken:  newAccessToken,
			RefreshToken: request.RefreshToken,
			TokenType:    "Bearer",
			ExpiresIn:    int64(cfg.AccessTokenExp * 60), // 转换为秒
		}, nil
	}
}

// VerifyToken 验证token并获取用户信息
func (s *authService) VerifyToken(token string) (*serializers.AuthUserInfoResponse, error) {
	// 首先尝试解析为访问令牌
	accessClaims, accessErr := jwt.ParseAccessToken(token)
	// 然后尝试解析为刷新令牌
	refreshClaims, refreshErr := jwt.ParseRefreshToken(token)

	// 如果两种令牌都解析失败，则返回错误
	if accessErr != nil && refreshErr != nil {
		return nil, errors.New("无效的令牌")
	}

	var userID uint64
	var isRefreshToken bool

	// 确定令牌类型和用户ID
	if accessErr == nil {
		userID = accessClaims.UserID
		isRefreshToken = false
	} else {
		userID = refreshClaims.UserID
		isRefreshToken = true
	}

	cfg := config.GetConfig().JWT

	// 根据配置决定是否使用高级认证功能
	if cfg.EnableAdvancedAuth {
		// 检查令牌是否在黑名单中
		isBlacklisted, err := s.authRepo.IsTokenBlacklisted(token)
		if err != nil {
			return nil, fmt.Errorf("检查令牌黑名单失败: %v", err)
		}
		if isBlacklisted {
			return nil, errors.New("令牌已失效")
		}

		// 如果是刷新令牌，需要验证会话
		if isRefreshToken {
			session, err := s.authRepo.GetLoginSessionByRefreshToken(token)
			if err != nil {
				return nil, errors.New("无效的刷新令牌")
			}

			// 验证会话是否属于同一用户
			if session.UserID != userID {
				return nil, errors.New("无效的刷新令牌")
			}

			// 更新会话活动时间
			if err := s.authRepo.UpdateLoginSessionActivity(session.ID, time.Now()); err != nil {
				// 记录错误但不影响正常流程
				fmt.Printf("更新会话活动时间失败: %v", err)
			}
		} else {
			// 如果是访问令牌，检查登录会话
			session, err := s.authRepo.GetLoginSessionByAccessToken(token)
			if err != nil {
				return nil, errors.New("无效的访问令牌")
			}

			// 更新会话活动时间
			if err := s.authRepo.UpdateLoginSessionActivity(session.ID, time.Now()); err != nil {
				// 记录错误但不影响正常流程
				fmt.Printf("更新会话活动时间失败: %v", err)
			}
		}
	}

	// 获取用户信息
	user, err := s.authRepo.GetUserByID(userID)
	if err != nil {
		return nil, errors.New("用户不存在")
	}

	// 检查用户状态
	if user.Status != 1 {
		return nil, errors.New("用户账号已被禁用")
	}

	// 转换为响应格式
	return serializers.ConvertUserToAuthUserInfoResponse(user), nil
}

// Logout 用户登出
func (s *authService) Logout(accessToken string) error {
	// 解析访问令牌
	claims, err := jwt.ParseAccessToken(accessToken)
	if err != nil {
		return errors.New("无效的访问令牌")
	}

	cfg := config.GetConfig().JWT

	// 根据配置决定是否使用高级认证功能
	if cfg.EnableAdvancedAuth {
		// 获取登录会话
		session, err := s.authRepo.GetLoginSessionByAccessToken(accessToken)
		if err != nil {
			return errors.New("无效的访问令牌")
		}

		// 停用登录会话
		if err := s.authRepo.DeactivateLoginSession(session.ID); err != nil {
			return fmt.Errorf("停用登录会话失败: %v", err)
		}

		// 将访问令牌和刷新令牌加入黑名单
		accessTokenExpiresAt := time.Now().Add(time.Duration(cfg.AccessTokenExp) * time.Minute)
		refreshTokenExpiresAt := time.Now().Add(time.Duration(cfg.RefreshTokenExp) * time.Minute)

		if err := s.authRepo.AddTokenToBlacklist(accessToken, "access", claims.UserID, "logout", accessTokenExpiresAt); err != nil {
			return fmt.Errorf("添加访问令牌到黑名单失败: %v", err)
		}

		if err := s.authRepo.AddTokenToBlacklist(session.RefreshToken, "refresh", claims.UserID, "logout", refreshTokenExpiresAt); err != nil {
			return fmt.Errorf("添加刷新令牌到黑名单失败: %v", err)
		}
	}

	// 如果高级功能关闭，登出操作只是一个空操作，客户端删除本地token即可
	return nil
}
